package com.moduls.interfaceFunction.mybatis;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.itfsw.mybatis.generator.plugins.utils.XmlElementGeneratorTools;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.OutputUtilities;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.*;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
public class BatchInsertAndWherePlugin extends PluginAdapter {

    /**
     * {@inheritDoc}
     */
    public boolean validate(List<String> warnings) {
        return true;
    }


    public static Method generateMethod(String methodName, JavaVisibility visibility, FullyQualifiedJavaType returnType, Parameter... parameters) {
        Method method = new Method(methodName);
        method.setVisibility(visibility);
        method.setReturnType(returnType);
        if (parameters != null) {
            for (Parameter parameter : parameters) {
                method.addParameter(parameter);
            }
        }

        return method;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {


        // 1. batchInsert
        addselectAllWhereMethod(interfaze, topLevelClass, introspectedTable);
        addbatchInsertMethod(interfaze, topLevelClass, introspectedTable);
        return true;
    }

    private void addselectAllWhereMethod(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType listType = FullyQualifiedJavaType.getNewListInstance();
        listType.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
        Method mBatchInsert = generateMethod(
                "selectAllWhere",
                JavaVisibility.DEFAULT,
                listType,
                new Parameter(FullyQualifiedJavaType.getStringInstance(), "wheresql")

        );
        interfaze.addMethod(mBatchInsert);
        interfaze.addAnnotation("@Repository");
        interfaze.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Repository"));
    }
    private void addbatchInsertMethod(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {


       FullyQualifiedJavaType listType = FullyQualifiedJavaType.getNewListInstance();

        listType.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
        Method mBatchInsert = generateMethod(
                "batchInsert",
                JavaVisibility.DEFAULT,
                FullyQualifiedJavaType.getIntInstance(),
                new Parameter(listType,  "list", "@Param(\"list\")")

        );
        interfaze.addMethod(mBatchInsert);
       // interfaze.addAnnotation("@Repository");
        interfaze.addImportedType(new FullyQualifiedJavaType("org.apache.ibatis.annotations.Param"));
    }
    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
        addselectAllWhereXml(document, introspectedTable);
        addbatchInsertXml(document, introspectedTable);
        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }

    private void addselectAllWhereXml(Document document, IntrospectedTable introspectedTable) {
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();//数据库表名
        XmlElement parentElement = document.getRootElement();
        XmlElement selectElement = new XmlElement("select");
        selectElement.addAttribute(new Attribute("id", "selectAllWhere"));
        selectElement.addAttribute(new Attribute("resultMap", "BaseResultMap"));
        selectElement.addAttribute(new Attribute("parameterType", "java.lang.String"));
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();
        selectElement.addElement(
                new TextElement(
                        "select *   from " + tableName + " where  ${_parameter}"
                ));

        parentElement.addElement(selectElement);
    }

    private void addbatchInsertXml(Document document, IntrospectedTable introspectedTable) {

// 1. batchInsert
        XmlElement batchInsertEle = new XmlElement("insert");
        batchInsertEle.addAttribute(new Attribute("id", "batchInsert"));
        // 参数类型
        batchInsertEle.addAttribute(new Attribute("parameterType", "map"));


        batchInsertEle.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));

       Object[] objects= introspectedTable.getAllColumns().parallelStream().map(IntrospectedColumn::getActualColumnName).toArray();

        batchInsertEle.addElement(new TextElement("("));
        batchInsertEle.addElement(new TextElement(StringUtils.join(objects,",")));

        batchInsertEle.addElement(new TextElement(")"));

        // 添加foreach节点
        XmlElement foreachElement = new XmlElement("foreach");
        foreachElement.addAttribute(new Attribute("collection", "list"));
        foreachElement.addAttribute(new Attribute("item", "item"));
        foreachElement.addAttribute(new Attribute("separator", ","));
       List<TextElement>  textElements= generateCommColumns(introspectedTable.getAllColumns(),"item.",true,2);
        for (Element element : textElements) {
            foreachElement.addElement(element);
        }

        // values 构建
        batchInsertEle.addElement(new TextElement("values"));
        batchInsertEle.addElement(foreachElement);
        if (context.getPlugins().sqlMapInsertElementGenerated(batchInsertEle, introspectedTable)) {
            document.getRootElement().addElement(batchInsertEle);

        }
    }
    private static List<TextElement> generateCommColumns(List<IntrospectedColumn> columns, String prefix, boolean bracket, int type) {
        List<TextElement> list = new ArrayList();
        StringBuilder sb = new StringBuilder(bracket ? "(" : "");
        Iterator columnIterator = columns.iterator();

        while(columnIterator.hasNext()) {
            IntrospectedColumn introspectedColumn = (IntrospectedColumn)columnIterator.next();
            switch(type) {
                case 1:
                    sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
                    break;
                case 2:
                    sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, prefix));
                    break;
                case 3:
                    sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
                    sb.append(" = ");
                    sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, prefix));
            }

            if (columnIterator.hasNext()) {
                sb.append(", ");
            }

            if (type != 1 && type != 2) {
                list.add(new TextElement(sb.toString()));
                sb.setLength(0);
            } else if (sb.length() > 80) {
                list.add(new TextElement(sb.toString()));
                sb.setLength(0);
                OutputUtilities.xmlIndent(sb, 1);
            }
        }

        if (sb.length() > 0 || bracket) {
            list.add(new TextElement(sb.append(bracket ? ")" : "").toString()));
        }

        return list;
    }
}
